home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 6 code / TCP / NewsWatcher / NW Source / Shared Code / Reusable Source / windutil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-21  |  14.3 KB  |  522 lines  |  [TEXT/MMCC]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     windutil.c
  4.  
  5.     This reusable module contains miscellaneous window management 
  6.     utility routines.
  7.     
  8.     Copyright © 1994-1995, Northwestern University.
  9.  
  10. ----------------------------------------------------------------------------*/
  11.  
  12. #include "def.h"
  13. #include "windutil.h"
  14. #include "drawutil.h"
  15. #include "memutil.h"
  16.  
  17.  
  18.  
  19. typedef struct TWindowRecordStorage {
  20.     CWindowRecord storage;                    /* window record storage */
  21.     Boolean fromFreeList;                    /* true if storage obtained from free list */
  22.     struct TWindowRecordStorage *next;        /* pointer to next available free buffer */
  23. } TWindowRecordStorage;
  24.  
  25.  
  26.  
  27. static TWindowRecordStorage *freeWindowRecordStorage = nil;    /* pointer to first free buffer */
  28.  
  29.  
  30.  
  31. /*----------------------------------------------------------------------------
  32.     MyFrontWindow 
  33.     
  34.     Get the frontmost window which belongs to the application.
  35.     
  36.     Exit:    function result = pointer to window record, or nil if none.
  37. ----------------------------------------------------------------------------*/
  38.  
  39. WindowPtr MyFrontWindow (void)
  40. {
  41.     WindowPeek windPeek;
  42.     
  43.     windPeek = (WindowPeek)FrontWindow();
  44.     while (windPeek != nil && windPeek->windowKind < 0) 
  45.         windPeek = windPeek->nextWindow;
  46.     return (WindowPtr)windPeek;
  47. }
  48.  
  49.  
  50.  
  51. /*----------------------------------------------------------------------------
  52.     InitializeWindowRecordStorage
  53.     
  54.     Preallocate window record storage buffers in high memory.
  55.     
  56.     Entry:    maxWindows = number of buffers to allocate.
  57.     
  58.     Exit:    function result = error code.
  59. ----------------------------------------------------------------------------*/
  60.  
  61. OSErr InitializeWindowRecordStorage (short maxWindows)
  62. {
  63.     short i;
  64.     Handle h;
  65.     TWindowRecordStorage **storage;
  66.     OSErr err = noErr;
  67.     
  68.     for (i = 0; i < maxWindows; i++) {
  69.         err = MyNewHandle(sizeof(TWindowRecordStorage), &h);
  70.         if (err != noErr) return err;
  71.         MyHLockHi(h);
  72.         storage = (TWindowRecordStorage**)h;
  73.         (**storage).next = freeWindowRecordStorage;
  74.         (**storage).fromFreeList = true;
  75.         freeWindowRecordStorage = *storage;
  76.     }
  77.     return noErr;
  78. }
  79.  
  80.  
  81.  
  82. /*----------------------------------------------------------------------------
  83.     MyNewWindow
  84.     
  85.     Create a new window. The window is a color window if we have color QD,
  86.     otherwise it's a black and white window.
  87.     
  88.     Entry:    rBounds = bounding rectangle in global coordinates.
  89.             title = Pascal format window title string.
  90.             visFlag = true to draw window, false to not draw window.
  91.             wDefProcID = window definition ID.
  92.             behind = -1 if in front, nil if in back, else pointer to window
  93.                 behind which this one will be placed.
  94.             goAwayFlag = true if window has close box.
  95.             refCon = application-defined reference.
  96.     
  97.     Exit:    function result = error code.
  98.             *wind = pointer to new window.
  99. ----------------------------------------------------------------------------*/
  100.  
  101. OSErr MyNewWindow (Rect *rBounds, Str255 title, Boolean visFlag, short wDefProcID,
  102.     WindowPtr behind, Boolean goAwayFlag, long refCon, WindowPtr *wind)
  103. {
  104.     TWindowRecordStorage *storage;
  105.     OSErr err = noErr;
  106.         
  107.     storage = freeWindowRecordStorage;
  108.     if (storage == nil) {
  109.         err = MyNewPtr(sizeof(TWindowRecordStorage), &storage);
  110.         if (err != noErr) return err;
  111.         storage->fromFreeList = false;
  112.     } else {
  113.         freeWindowRecordStorage = storage->next;
  114.     }
  115.     if (HasColorQD()) {
  116.         *wind = NewCWindow((CWindowRecord*)storage, rBounds, title, visFlag,
  117.             wDefProcID, behind, goAwayFlag, refCon);
  118.     } else {
  119.         *wind = NewWindow((CWindowRecord*)storage, rBounds, title, visFlag,
  120.             wDefProcID, behind, goAwayFlag, refCon);
  121.     }
  122.     
  123.     return noErr;
  124. }
  125.  
  126.  
  127.  
  128. /*----------------------------------------------------------------------------
  129.     MyDisposeWindow
  130.     
  131.     Dispose a window.
  132.     
  133.     Entry:    wind = pointer to window.
  134. ----------------------------------------------------------------------------*/
  135.  
  136. void MyDisposeWindow (WindowPtr wind)
  137. {
  138.     TWindowRecordStorage *storage;
  139.     
  140.     if (wind == nil) return;
  141.     storage = (TWindowRecordStorage*)wind;
  142.     CloseWindow(wind);
  143.     if (storage->fromFreeList) {
  144.         storage->next = freeWindowRecordStorage;
  145.         freeWindowRecordStorage = storage;
  146.     } else {
  147.         MyDisposePtr(storage);
  148.     }
  149. }
  150.  
  151.  
  152.  
  153. /*----------------------------------------------------------------------------
  154.     IsDAWindow 
  155.     
  156.     Check to see if a window belongs to a desk accessory.
  157.             
  158.     Entry:    wind = pointer to window.
  159.     
  160.     Exit:    function result = true if window belongs to a DA.
  161. ----------------------------------------------------------------------------*/
  162.  
  163. Boolean IsDAWindow (WindowPtr wind)
  164. {
  165.     if (wind == nil) {
  166.         return false;
  167.     } else {
  168.         return ((WindowPeek)wind)->windowKind < 0;
  169.     }
  170. }
  171.  
  172.  
  173.  
  174. /*----------------------------------------------------------------------------
  175.     GetWindRegionRects
  176.     
  177.     Return the bounding rects of a window's content and structure regions.
  178.     
  179.     Entry:    wind = pointer to window.
  180.     
  181.     Exit:    contRect = content region bounding rect.
  182.             strucRect = structure region bounding rect.
  183.                 
  184.     Adapted from Dean Yu's code in Develop #17.
  185. ----------------------------------------------------------------------------*/
  186.  
  187. void GetWindRegionRects (WindowPtr wind, Rect *contRect, Rect *strucRect)
  188. {
  189.     GrafPtr port;
  190.     RgnHandle contRgn, strucRgn;
  191.     Rect portRect, userState, stdState;
  192.     WStateData **wState;
  193.     
  194.     GetPort(&port);
  195.     SetPort(wind);
  196.     wState = (WStateData**)((WindowPeek)wind)->dataHandle;
  197.     userState = (**wState).userState;
  198.     stdState = (**wState).stdState;
  199.     if (((WindowPeek)wind)->visible) {
  200.         contRgn = ((WindowPeek)wind)->contRgn;
  201.         strucRgn = ((WindowPeek)wind)->strucRgn;
  202.         *contRect = (**contRgn).rgnBBox;
  203.         *strucRect = (**strucRgn).rgnBBox;
  204.     } else {
  205.         portRect = wind->portRect;
  206.         LocalToGlobalRect(&portRect);
  207.         MoveWindow(wind, -0x4000, -0x4000, false);
  208.         ShowHide(wind, true);
  209.         contRgn = ((WindowPeek)wind)->contRgn;
  210.         strucRgn = ((WindowPeek)wind)->strucRgn;
  211.         *contRect = (**contRgn).rgnBBox;
  212.         *strucRect = (**strucRgn).rgnBBox;
  213.         OffsetRect(contRect, portRect.left + 0x4000, portRect.top + 0x4000);
  214.         OffsetRect(strucRect, portRect.left + 0x4000, portRect.top + 0x4000);
  215.         ShowHide(wind, false);
  216.         MoveWindow(wind, portRect.left, portRect.top, false);
  217.     }
  218.     (**wState).userState = userState;
  219.     (**wState).stdState = stdState;
  220.     SetPort(port);
  221. }
  222.  
  223.  
  224.  
  225. /*----------------------------------------------------------------------------
  226.     GetDominantScreen
  227.     
  228.     Return the screen with the maximum intersection with a window.
  229.     
  230.     Entry:    wind = pointer to window.
  231.     
  232.     Exit:    screenRect = dominant screen's rectangle.
  233.             mainScreen = true if main screen (with menu bar).
  234.             onOneScreen = true if window completely contained on one screen.
  235.                 
  236.     Adapted from Dean Yu's code in Develop #17.
  237. ----------------------------------------------------------------------------*/
  238.  
  239. typedef struct TGetDominantScreenUserData {
  240.     GDHandle mainDevice;
  241.     GDHandle maxDevice;
  242.     long maxArea;
  243.     Rect windBounds;
  244. } TGetDominantScreenUserData;
  245.  
  246. static pascal void GetDominantScreenOneDevice (short depth, short deviceFlags,
  247.     GDHandle targetDevice, long userData)
  248. {
  249.     TGetDominantScreenUserData *ud;
  250.     Rect r, deviceRect;
  251.     long area;
  252.     
  253.     ud = (TGetDominantScreenUserData*)userData;
  254.     deviceRect = (**targetDevice).gdRect;
  255.     if (targetDevice == ud->mainDevice) deviceRect.top += GetMBarHeight();
  256.     SectRect(&ud->windBounds, &deviceRect, &r);
  257.     OffsetRect(&r, -r.left, -r.top);
  258.     area = (long)r.right * (long)r.bottom;
  259.     if (area > ud->maxArea) {
  260.         ud->maxArea = area;
  261.         ud->maxDevice = targetDevice;
  262.     }
  263. }
  264.  
  265. void GetDominantScreen (WindowPtr wind, Rect *screenRect, Boolean *mainScreen,
  266.     Boolean *onOneScreen)
  267. {
  268.     GrafPtr port;
  269.     RgnHandle rgn;
  270.     Rect contRect, strucRect, deviceLoopRect;
  271.     TGetDominantScreenUserData ud;
  272.     static DeviceLoopDrawingUPP upp = nil;
  273.     
  274.     if (upp == nil) upp = NewDeviceLoopDrawingProc(GetDominantScreenOneDevice);
  275.     
  276.     if (wind == nil) {
  277.         if (!HasColorQD()) {
  278.             *screenRect = qd.screenBits.bounds;
  279.         } else {
  280.             ud.mainDevice = GetMainDevice();
  281.             *screenRect = (**ud.mainDevice).gdRect;
  282.         }
  283.         *mainScreen = true;
  284.         *onOneScreen = true;
  285.         return;
  286.     }
  287.         
  288.     GetPort(&port);
  289.     SetPort(wind);
  290.     GetWindRegionRects(wind, &contRect, &strucRect);
  291.     if (!HasColorQD()) {
  292.         *screenRect = qd.screenBits.bounds;
  293.         *mainScreen = true;
  294.         goto exit;
  295.     }
  296.     ud.mainDevice = GetMainDevice();
  297.     ud.maxDevice = ud.mainDevice;
  298.     ud.maxArea = 0;
  299.     rgn = NewRgn();
  300.     SectRgn(GetGrayRgn(), ((WindowPeek)wind)->contRgn, rgn);
  301.     if (EmptyRgn(rgn)) {
  302.         ud.windBounds = strucRect;
  303.     } else {
  304.         ud.windBounds = contRect;
  305.     }
  306.     deviceLoopRect = ud.windBounds;
  307.     GlobalToLocalRect(&deviceLoopRect);
  308.     RectRgn(rgn, &deviceLoopRect);
  309.     DeviceLoop(rgn, upp, (long)&ud, singleDevices);
  310.     DisposeRgn(rgn);
  311.     *screenRect = (**ud.maxDevice).gdRect;
  312.     *mainScreen = ud.maxDevice == ud.mainDevice;
  313.     
  314. exit:
  315.  
  316.     if (*mainScreen) strucRect.top -= GetMBarHeight();
  317.     *onOneScreen = strucRect.top >= screenRect->top && 
  318.         strucRect.bottom <= screenRect->bottom &&
  319.         strucRect.left >= screenRect->left &&
  320.         strucRect.right <= screenRect->right;
  321.     SetPort(port);
  322. }
  323.  
  324.  
  325.  
  326. /*----------------------------------------------------------------------------
  327.     WindOnScreen
  328.     
  329.     Check to see if a window is completely within a single screen.
  330.     
  331.     Entry:    wind = pointer to window.
  332.     
  333.     Exit:    function result = true if window is completely within a
  334.                 single screen.
  335. ----------------------------------------------------------------------------*/
  336.  
  337. Boolean WindOnScreen (WindowPtr wind)
  338. {
  339.     Rect screenRect;
  340.     Boolean mainScreen, onOneScreen;
  341.     
  342.     GetDominantScreen(wind, &screenRect, &mainScreen, &onOneScreen);
  343.     return onOneScreen;
  344. }
  345.  
  346.  
  347.  
  348. /*----------------------------------------------------------------------------
  349.     StaggerWindow
  350.     
  351.     Stagger a new window.
  352.     
  353.     Entry:    wind = pointer to window.
  354.             width = window width.
  355.             height = window height.
  356.             offsetFrom = pointer to window from which this window should be
  357.                 offset, or nil if none.
  358.             dontCoverFinderIcons = true to avoid covering up Finder icons.
  359. ----------------------------------------------------------------------------*/
  360.  
  361. void StaggerWindow (WindowPtr wind, short width, short height, WindowPtr offsetFrom,
  362.     Boolean dontCoverFinderIcons)
  363. {
  364.     Rect screenRect, r, contRect, strucRect;
  365.     WStateData **wState;
  366.     GrafPtr port;
  367.     Boolean mainScreen, onOneScreen, topLeft = false;
  368.  
  369.     GetPort(&port);
  370.     SetPort(wind);
  371.     SizeWindow(wind, width, height, false);
  372.     GetWindRegionRects(wind, &contRect, &strucRect);
  373.     GetDominantScreen(offsetFrom, &screenRect, &mainScreen, &onOneScreen);
  374.     if (mainScreen) {
  375.         screenRect.top += GetMBarHeight();
  376.     }
  377.     if (offsetFrom == nil) {
  378.         topLeft = true;
  379.     } else {
  380.         r = offsetFrom->portRect;
  381.         SetPort(offsetFrom);
  382.         LocalToGlobalRect(&r);
  383.         SetPort(wind);
  384.         MoveWindow(wind, r.left + 20, r.top + 20, false);
  385.         if (!WindOnScreen(wind)) {
  386.             topLeft = true;
  387.         } else if (dontCoverFinderIcons && mainScreen && 
  388.             screenRect.right - screenRect.left > 576) 
  389.         {
  390.             r = wind->portRect;
  391.             LocalToGlobalRect(&r);
  392.             if (r.right + 64 > screenRect.right) topLeft = true;
  393.         }
  394.     }
  395.     if (topLeft) {
  396.         MoveWindow(wind,
  397.             screenRect.left + contRect.left - strucRect.left + 4,
  398.             screenRect.top + contRect.top - strucRect.top + 4,
  399.             false);
  400.     }
  401.     
  402.     wState = (WStateData**)((WindowPeek)wind)->dataHandle;
  403.     r = wind->portRect;
  404.     LocalToGlobalRect(&r);
  405.     (**wState).userState = r;
  406.     SetPort(port);
  407. }
  408.  
  409.  
  410.  
  411. /*----------------------------------------------------------------------------
  412.     CalculateZoomRect
  413.     
  414.     Calculate the zoomed rectangle for a window.
  415.     
  416.     Entry:    wind = pointer to window.
  417.             width = desired width of zoomed window if infinite screen.
  418.             height = desired height of zoomed window if infinite screen.
  419.             dontCoverFinderIcons = true to avoid covering up Finder icons.
  420.     
  421.     Exit:    *zoomRect = zoomed rectangle for the window.
  422. ----------------------------------------------------------------------------*/
  423.  
  424. void CalculateZoomRect (WindowPtr wind, short width, short height, 
  425.     Rect *zoomRect, Boolean dontCoverFinderIcons)
  426. {
  427.     Rect windRect, screenRect, contRect, strucRect;
  428.     short leftDiff, topDiff, rightDiff, bottomDiff;
  429.     short screenWidth, screenHeight;
  430.     Boolean mainScreen, onOneScreen;
  431.  
  432.     GetDominantScreen(wind, &screenRect, &mainScreen, &onOneScreen);
  433.     GetWindRegionRects(wind, &contRect, &strucRect);
  434.     leftDiff = contRect.left - strucRect.left;
  435.     topDiff = contRect.top - strucRect.top;
  436.     rightDiff = strucRect.right - contRect.right;
  437.     bottomDiff = strucRect.bottom - contRect.bottom;
  438.     
  439.     if (mainScreen) {
  440.         screenRect.top += GetMBarHeight();
  441.         if (dontCoverFinderIcons && screenRect.right - screenRect.left > 576) 
  442.             screenRect.right -= 64;
  443.     }
  444.     InsetRect(&screenRect, 4, 4);
  445.     
  446.     width += leftDiff + rightDiff;
  447.     if (height < 0x7000) height += topDiff + bottomDiff;
  448.     screenWidth = screenRect.right - screenRect.left;
  449.     screenHeight = screenRect.bottom - screenRect.top;
  450.     if (width > screenWidth) width = screenWidth;
  451.     if (height > screenHeight) height = screenHeight;
  452.  
  453.     windRect = wind->portRect;
  454.     LocalToGlobalRect(&windRect);
  455.     windRect.left -= leftDiff;
  456.     windRect.top -= topDiff;
  457.     windRect.right = windRect.left + width;
  458.     windRect.bottom = windRect.top + height;
  459.     
  460.     if (windRect.left < screenRect.left)
  461.         OffsetRect(&windRect, screenRect.left - windRect.left, 0);
  462.     if (windRect.right > screenRect.right) 
  463.         OffsetRect(&windRect, screenRect.right - windRect.right, 0);
  464.     if (windRect.top < screenRect.top)
  465.         OffsetRect(&windRect, 0, screenRect.top - windRect.top);
  466.     if (windRect.bottom > screenRect.bottom)
  467.         OffsetRect(&windRect, 0, screenRect.bottom - windRect.bottom);
  468.         
  469.     windRect.left += leftDiff;
  470.     windRect.top += topDiff;
  471.     windRect.right -= rightDiff;
  472.     windRect.bottom -= bottomDiff;
  473.         
  474.     *zoomRect = windRect;
  475. }
  476.  
  477.  
  478.  
  479. /*----------------------------------------------------------------------------
  480.     WindRectEqualRect 
  481.     
  482.     Check to see if a window's rectangle equals a rectangle.
  483.             
  484.     Entry:    wind = pointer to window.
  485.             r = pointer to rectangle in global coords.
  486.             
  487.     Exit:    function result = true if window's rectangle is equal to
  488.                 the specified global rectange.
  489. ----------------------------------------------------------------------------*/
  490.  
  491. Boolean WindRectEqualRect (WindowPtr wind, Rect *r)
  492. {
  493.     GrafPtr port;
  494.     Rect windRect;
  495.     
  496.     GetPort(&port);
  497.     windRect = wind->portRect;
  498.     SetPort(wind);
  499.     LocalToGlobalRect(&windRect);
  500.     SetPort(port);
  501.     return EqualRect(&windRect, r);
  502. }
  503.  
  504.  
  505.  
  506. /*----------------------------------------------------------------------------
  507.     SetWindowNeedsZooming 
  508.     
  509.     Set a window standard state to (0,0,0,0) to force a zoom out on the next
  510.     zoom.
  511.             
  512.     Entry:    wind = pointer to window.
  513. ----------------------------------------------------------------------------*/
  514.  
  515. void SetWindowNeedsZooming (WindowPtr wind)
  516. {
  517.     WStateData **wState;
  518.     
  519.     wState = (WStateData**)((WindowPeek)wind)->dataHandle;
  520.     SetRect(&(**wState).stdState, 0, 0, 0, 0);
  521. }
  522.